#include "loadobj.h"
#include "ui_loadobj.h"

LoadObj::LoadObj(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::LoadObj)
{
    ui->setupUi(this);
    initializateOn3DView();
    //db.m_windowOn3D->installEventFilter(this);
}

LoadObj::~LoadObj()
{
    delete ui;
}

void LoadObj::initializateOn3DView()
{
    db.m_windowOn3D = new Self3DWindow(); //Qt3DExtras::Qt3DWindow
    db.m_rootEntity = new QtEntity();     //Qt3DCore::QEntity
    db.m_material = new QtMaterial();     //Qt3DRender::QMaterial
    db.m_trans = new QtTransform();       //Qt3DCore::QTransform
    db.m_input = new QtInputAspect();     //Qt3DInput::QInputAspect
    db.m_picker = new QtObjectPicker(db.m_rootEntity);   //Qt3DRender::QObjectPicker
    db.m_scene = new QtSceneLoader(db.m_rootEntity);     //Qt3DRender::QSceneLoader

//    m_backColor = Qt::gray;
    m_backColor = QColor(11,15,18);
    m_lightColor = Qt::white;
    m_lightSource = 2;       //光源，1点光2定向光3聚集光
    m_lightIntensity = 2.0;  //光的强度
    m_moveFunc = 1;    //鼠标拖动的功能:1旋转2平移

    m_XAngle=0;    //X轴旋转角度    272
    m_YAngle=200;    //Y轴旋转角度    200
    m_ZAngle=0;      //Z轴旋转角度
    m_zoomVal = 0.002;//模型缩放比例   0.05
    m_XTrans = 0.0;  //X轴方向平移观察
    m_YTrans = 10.0;  //Y轴方向平移观察  10
    m_ZTrans = 0.0;  //Z轴方向平移观察

    m_XLigRota = 100.0;
    m_YLigRota = 100.0;
    m_ZLigRota = 100.0;

    connect(db.m_windowOn3D,&Self3DWindow::sigPosition,this,&LoadObj::slotTransPos);      //获取鼠标单击处的坐标点
    connect(db.m_windowOn3D,&Self3DWindow::sigMouseDrag,this,&LoadObj::slotMouseDrag);    //鼠标拖动功能处理
    connect(db.m_windowOn3D,&Self3DWindow::sigZoom,this,&LoadObj::slotZoom);              //鼠标滚轮缩放
    connect(db.m_scene,&QtSceneLoader::statusChanged,this,&LoadObj::slotLoadStat);        //加载模型状态

    //只有鼠标单击实体对象时，才会发射下面的信号，只单击3D场景视图窗口view，不会发射下面的信号.  鼠标单击时，依次发射pressed、released、clicked信号
    connect(db.m_picker,&QtObjectPicker::pressed,this,&LoadObj::slotPickerPressed);   //鼠标键按下，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::released,this,&LoadObj::slotPickerReleased); //鼠标键松开，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::clicked,this,&LoadObj::slotPickerClicked);   //鼠标键按下并松开后，才会发射此信号，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::moved,this,&LoadObj::slotPickerMoved);
    connect(db.m_picker,&QtObjectPicker::exited,this,&LoadObj::slotPickerExited);
}

void LoadObj::load3DModel(const QString &obj_url)
{
    //1.创建和设置3D场景视图窗口view, 已有m_windowOn3D, 这里是设置
    //db.m_windowOn3D->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
    db.m_windowOn3D->defaultFrameGraph()->setClearColor(m_backColor);

//    // 设置背景图片
//    Qt3DRender::QTextureImage *backgroundImage = new Qt3DRender::QTextureImage();
//    backgroundImage->setSource(QUrl(QStringLiteral(":/images/rocketModelBack.png")));
//    Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D();
//    texture->addTextureImage(backgroundImage);
//    Qt3DExtras::QTextureMaterial *material = new Qt3DExtras::QTextureMaterial();
//    material->setTexture(texture);


////    QImage backgroundImage(":/path/to/image"); // 加载背景图片
//    Qt3DRender::QLayer *backgroundLayer = new Qt3DRender::QLayer(); // 创建一个图层
//    backgroundLayer->setObjectName("backgroundLayer");
//    Qt3DRender::QMaterial *backgroundMaterial = new Qt3DRender::QMaterial(backgroundLayer);
//    Qt3DRender::QTexture2D *backgroundTexture = new Qt3DRender::QTexture2D(backgroundMaterial);
//    Qt3DRender::QTextureImage *backgroundTextureImage = new Qt3DRender::QTextureImage(backgroundTexture);
//    backgroundTextureImage->setSource(QUrl(":/path/to/image"));
//    backgroundTexture->addTextureImage(backgroundTextureImage);
//    Qt3DRender::QMaterialProperties *backgroundProperties = new Qt3DRender::QMaterialProperties(backgroundMaterial);
//    backgroundProperties->setShaderProgram(QStringLiteral("image"));
//    backgroundMaterial->addParameter(backgroundTexture);




    //2.如果将3d放置在界面中，则需要创建一个widget来“装”它
    QWidget *container = QWidget::createWindowContainer(db.m_windowOn3D);
    QSize screenSize = db.m_windowOn3D->screen()->size();   //设置场景大小
    container->setMinimumSize(QSize(200, 100));   //当你缩小对话框时，你希望它最小是多少
    container->setMaximumSize(screenSize);        //当你缩小对话框时，你希望它最大是多少

    //3.需要一个主窗口Widget，进行适当布局
    setWindowTitle(QStringLiteral("Load 3D Model"));  //给主窗口设置一个标题
    QHBoxLayout *hLayout = new QHBoxLayout(this);
    hLayout->setMargin(0);
    hLayout->setSpacing(0);
    hLayout->setContentsMargins(0,0,0,0);
//    QVBoxLayout *vLayout = new QVBoxLayout();
//    vLayout->setAlignment(Qt::AlignTop);

    //4.将3d场景veiw放到主窗口widget布局中
    hLayout->addWidget(container, 1);
//    hLayout->addLayout(vLayout);

    //5.创建根实体（Root Entity）对象，即所谓的“画布”，并将其设置到3D场景视图中. 这里已有m_rootEntity,只是将其设置到3D场景视图中,并设置输入
    db.m_windowOn3D->setRootEntity(db.m_rootEntity);
    db.m_windowOn3D->registerAspect(db.m_input); // 设置3d场景的输入. 要不要这行代码都可以

    //6.设置相机属性
    QtCamera *cameraEntity = db.m_windowOn3D->camera();
    cameraEntity->lens()->setPerspectiveProjection(45.0f,16.0f/9.0f,0.1f,1000.0f);  //观测视角. 第1个参数设置离物体的观察距离，值越大，离的越远
    cameraEntity->setPosition(QVector3D(40.0f, 20.0f, -10.0f));  //设置相机摆放的上下左右位置，第1、3参数设置左右移动，第2参数设置上下移动
    cameraEntity->setUpVector(QVector3D(0, 1, 0));     //设置模型左右颠倒和上下颠倒的
    cameraEntity->setViewCenter(QVector3D(m_XTrans, m_YTrans, m_ZTrans));  //视角中心在哪里. 这里设置完后，还是可以通过鼠标来调整观察方向的

    //7.在根实体（Root Entity）对象,即“画布”中加入子实体“光照light”
    db.m_lightEntity = new Qt3DCore::QEntity(db.m_rootEntity);
    //定义一种光源对象
    if(m_lightSource == 1)
    {
        //Qt3DRender::QPointLight *poitLight = new Qt3DRender::QPointLight(m_lightEntity);
        Qt3DRender::QPointLight *poitLight = new Qt3DRender::QPointLight();  //点光
        poitLight->setColor(m_lightColor);       //光的颜色
        poitLight->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(poitLight);
    }
    else if(m_lightSource == 2)
    {
        //Qt3DRender::QDirectionalLight *direcLight = new Qt3DRender::QDirectionalLight(m_lightEntity);
        Qt3DRender::QDirectionalLight *direcLight = new Qt3DRender::QDirectionalLight();  //定向光
        direcLight->setColor(m_lightColor);       //光的颜色
        direcLight->setIntensity(m_lightIntensity);         //光的强度
        //qDebug()<<"DirectionalLight worldDirection:"<<direcLight->worldDirection();
        direcLight->setWorldDirection(QVector3D(-1, 0, 0));  //解决光照位置的问题
        db.m_lightEntity->addComponent(direcLight);
    }
    else if(m_lightSource == 3)
    {
        //Qt3DRender::QSpotLight *spotLight = new Qt3DRender::QSpotLight(m_lightEntity);
        Qt3DRender::QSpotLight *spotLight = new Qt3DRender::QSpotLight();  //聚集光
        spotLight->setColor(m_lightColor);       //光的颜色
        spotLight->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(spotLight);
    }
    //定义光照实体的变换（设置光照显示位置等）
    db.m_lightTrans = new Qt3DCore::QTransform(db.m_lightEntity);
    db.m_lightTrans->setTranslation(db.m_windowOn3D->camera()->position());
    //lightTransform->setTranslation(QVector3D(40.0f, 20.0f, -10.0f));
    db.m_lightTrans->setRotationX(m_XLigRota);
    db.m_lightTrans->setRotationY(m_YLigRota);
    db.m_lightTrans->setRotationZ(m_ZLigRota);
    db.m_lightEntity->addComponent(db.m_lightTrans);

    /*
    //8.绘制3D场景的实体图形，这里使用Qmesh加载obj文件
    Qt3DRender::QMesh *mesh = new Qt3DRender::QMesh();
    mesh->setSource(QUrl(obj_url));
    */

    //8.绘制3D场景的实体图形，这里使用QSceneLoader加载obj文件
//    Qt3DRender::QSceneLoader *sceneLoader = new Qt3DRender::QSceneLoader(db.m_rootEntity);
//    sceneLoader->setSource(QUrl(obj_url));
//    sceneLoader->setEnabled(true);
    db.m_scene->setSource(QUrl(obj_url));
    db.m_scene->setEnabled(true);

    /* 使用QSceneLoader,就不需要Material了
    //9.Material(表面贴图等材质显示)，有多种不同类型的材质可选. 仅有Mesh，实体只会显示一片黑，Material提供了实体表面的呈现
    //QPhongMaterial提供默认实现的光照效果,不进行其他设置的画默认是白色半粗糙的效果。
    Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial(db.m_rootEntity);
    material->setDiffuse(QColor(QRgb(0xa69929)));     //类似漫反射，也就是粗糙表面
    //material->setAmbient(QColor(QRgb(0xffffff)));     //在没有（或者说不考虑）其他光源的影响的情况下，物体本身的颜色。也就是你设置什么颜色就是什么颜色
    //material->setSpecular(QColor(QRgb(0xffffff)));   //镜面反射，也就是说像一面镜子，你给的光什么颜色它就呈现什么颜色
    material->setShininess(100.0f);   //设置物体表面的粗糙/反光程度，float类型，数值越大越光滑
    */

    //10.模型的缩放，加载的模型比较大，这里要缩小显示
    db.m_trans->setScale(m_zoomVal);
    db.m_trans->setTranslation(QVector3D(0.0f, 0.0f, 0.0f));

    //11.将各渲染组件加入到实体list中去
    //db.m_rootEntity->addComponent(mesh);
    //db.m_rootEntity->addComponent(material);
    db.m_rootEntity->addComponent(db.m_scene);
    db.m_rootEntity->addComponent(db.m_trans);
//    db.m_rootEntity->addComponent(material);

    //12.摄像机控制配置（这里配置以第一人称视角控制场景摄影机）.设置后，鼠标拖动就可以改变观察位置.
    Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(db.m_rootEntity);
    //camController->setCamera(db.m_windowOn3D->camera());

    //13.旋转调整实体
    db.m_trans->setRotationX(m_XAngle);
    db.m_trans->setRotationY(m_YAngle);
    db.m_rootEntity->addComponent(db.m_trans);

    //14.设置对象选择，场景拖拽
    db.m_picker->setDragEnabled(false);          //要加这个语句，且要设为true，否则鼠标拖动时不会发射moved信号
    db.m_picker->setHoverEnabled(false);         //启用鼠标悬浮响应。只有这样才可能会发射exited信号
    db.m_rootEntity->addComponent(db.m_picker);  //要有这个语句，否则鼠标动作时不会发射picker的相关信号
}

void LoadObj::reloadModel()
{
    delete db.m_windowOn3D;
    delete db.m_rootEntity;
    delete db.m_material;
    delete db.m_trans;
    delete db.m_input;
    delete db.m_picker;

    db.m_windowOn3D = new Self3DWindow(); //Qt3DExtras::Qt3DWindow
    db.m_rootEntity = new QtEntity();     //Qt3DCore::QEntity
    db.m_material = new QtMaterial();     //Qt3DRender::QMaterial
    db.m_trans = new QtTransform();       //Qt3DCore::QTransform
    db.m_input = new QtInputAspect();     //Qt3DInput::QInputAspect
    db.m_picker = new QtObjectPicker(db.m_rootEntity);   //Qt3DRender::QObjectPicker
    db.m_scene = new QtSceneLoader(db.m_rootEntity);     //Qt3DRender::QSceneLoader

    connect(db.m_windowOn3D,&Self3DWindow::sigPosition,this,&LoadObj::slotTransPos);      //获取鼠标单击处的坐标点
    connect(db.m_windowOn3D,&Self3DWindow::sigMouseDrag,this,&LoadObj::slotMouseDrag);    //鼠标拖动功能处理
    connect(db.m_windowOn3D,&Self3DWindow::sigZoom,this,&LoadObj::slotZoom);              //鼠标滚轮缩放
    connect(db.m_scene,&QtSceneLoader::statusChanged,this,&LoadObj::slotLoadStat);        //

    //只有鼠标单击实体对象时，才会发射下面的信号，只单击3D场景视图窗口view，不会发射下面的信号.  鼠标单击时，依次发射pressed、released、clicked信号
    connect(db.m_picker,&QtObjectPicker::pressed,this,&LoadObj::slotPickerPressed);   //鼠标键按下，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::released,this,&LoadObj::slotPickerReleased); //鼠标键松开，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::clicked,this,&LoadObj::slotPickerClicked);   //鼠标键按下并松开后，才会发射此信号，包括左键、右键、滚轮按下
    connect(db.m_picker,&QtObjectPicker::moved,this,&LoadObj::slotPickerMoved);
    connect(db.m_picker,&QtObjectPicker::exited,this,&LoadObj::slotPickerExited);

    QLayout *lay = layout();
    delete lay;
    load3DModel("qrc:/antenna_00.obj");
}

void LoadObj::slotLoadStat(Qt3DRender::QSceneLoader::Status status)
{
    if(status == Qt3DRender::QSceneLoader::Ready)
    {
        QStringList entryList = db.m_scene->entityNames();
        qDebug()<<"entryList:"<<entryList;
    }
}

void LoadObj::slotChangeBackColor(QColor color)
{
    m_backColor = color;
    db.m_windowOn3D->defaultFrameGraph()->setClearColor(color);
}

void LoadObj::slotChangeLightColor(QColor color)
{
    m_lightColor = color;

    Qt3DCore::QComponentVector compoVec = db.m_rootEntity->components();        //获取所有组件
//    db.m_rootEntity->removeComponent();   //移除光照组件

    if(m_lightSource == 1)
    {
        Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight();  //点光
        light->setColor(color);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 2)
    {
        Qt3DRender::QDirectionalLight *light = new Qt3DRender::QDirectionalLight();  //定向光
        light->setColor(color);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 3)
    {
        Qt3DRender::QSpotLight *light = new Qt3DRender::QSpotLight();  //聚集光
        light->setColor(color);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }

//    db.m_lightEntity->addComponent(db.m_rootEntity);
}

void LoadObj::slotChangeLightSource(int source)
{
    m_lightSource = source;

    Qt3DCore::QComponentVector compoVec = db.m_rootEntity->components();        //获取所有组件
//    db.m_rootEntity->removeComponent();   //移除光照组件
    if(source == 1)
    {
        Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight();  //点光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 2)
    {
        Qt3DRender::QDirectionalLight *light = new Qt3DRender::QDirectionalLight();  //定向光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 3)
    {
        Qt3DRender::QSpotLight *light = new Qt3DRender::QSpotLight();  //聚集光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(m_lightIntensity);         //光的强度
        db.m_lightEntity->addComponent(light);
    }

//    db.m_lightEntity->addComponent(db.m_rootEntity);
}

void LoadObj::slotChangeLightIntensity(int val)
{
    m_lightIntensity = val;

    Qt3DCore::QComponentVector compoVec = db.m_rootEntity->components();        //获取所有组件
//    db.m_rootEntity->removeComponent();   //移除光照组件
    if(m_lightSource == 1)
    {
        Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight();  //点光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(val);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 2)
    {
        Qt3DRender::QDirectionalLight *light = new Qt3DRender::QDirectionalLight();  //定向光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(val);         //光的强度
        db.m_lightEntity->addComponent(light);
    }
    else if(m_lightSource == 3)
    {
        Qt3DRender::QSpotLight *light = new Qt3DRender::QSpotLight();  //聚集光
        light->setColor(m_lightColor);         //光的颜色
        light->setIntensity(val);         //光的强度
        db.m_lightEntity->addComponent(light);
    }

//    db.m_lightEntity->addComponent(db.m_rootEntity);
}

void LoadObj::slotRotateX(int val)
{
    db.m_trans->setRotationX(val);
    db.m_rootEntity->addComponent(db.m_trans);
}

void LoadObj::slotRotateY(int val)
{
    db.m_trans->setRotationY(val);
    db.m_rootEntity->addComponent(db.m_trans);
}

void LoadObj::slotRotateZ(int val)
{
    db.m_trans->setRotationZ(val);
    db.m_rootEntity->addComponent(db.m_trans);
}

void LoadObj::slotTransPos(int xpos,int ypos)
{
    emit sigTransPos(xpos,ypos,m_YAngle);
}

void LoadObj::slotMouseDrag(int xOff,int yOff)
{
    if(m_moveFunc == 1)   //鼠标拖动旋转
    {
        int tAngle = m_YAngle + (xOff/10);
        if(tAngle < 0)
            m_YAngle = 360+tAngle;
        else if(tAngle > 360)
            m_YAngle = tAngle-360;
        else
            m_YAngle = tAngle;
        db.m_trans->setRotationY(m_YAngle);
        db.m_rootEntity->addComponent(db.m_trans);
    }
    else   //鼠标拖动平移  通过改变视觉中心来达到平移的效果
    {
//        m_XTrans = m_XTrans + xOff/10;
//        m_YTrans = m_YTrans + yOff/10;
//        m_ZTrans = (m_XTrans + m_YTrans)/2;
//        db.m_trans->setTranslation(QVector3D(m_XTrans, m_YTrans, m_ZTrans));
//        db.m_rootEntity->addComponent(db.m_trans);

        m_XTrans = m_XTrans - xOff/10;
        m_YTrans = m_YTrans - yOff/10;
        //m_ZTrans = (m_XTrans + m_YTrans)/2;
        QtCamera *cameraEntity = db.m_windowOn3D->camera();
        cameraEntity->setPosition(QVector3D(40.0f, 20.0f, -10.0f));  //设置相机摆放的上下左右位置，第1、3参数设置左右移动，第2参数设置上下移动
        cameraEntity->setUpVector(QVector3D(0, 1, 0));     //设置模型左右颠倒和上下颠倒的
        cameraEntity->setViewCenter(QVector3D(m_XTrans, m_YTrans, m_ZTrans));  //视角中心在哪里. 这里设置完后，还是可以通过鼠标来调整观察方向的
    }
}

void LoadObj::slotZoom(int flag)
{
    if(flag > 0)
        m_zoomVal = m_zoomVal *2;
    else
        m_zoomVal = m_zoomVal *0.5;
    db.m_trans->setScale(m_zoomVal);
    db.m_rootEntity->addComponent(db.m_trans);
}

void LoadObj::slotChangeMoveFunc(int func)
{
    m_moveFunc = func;
    //qDebug()<<"m_moveFunc:"<<m_moveFunc;
}

void LoadObj::slotLightRotateX(int val)
{
    db.m_lightTrans->setRotationX(val);
    db.m_lightEntity->addComponent(db.m_lightTrans);
    qDebug()<<"light rotate X:"<<val;
}

void LoadObj::slotLightRotateY(int val)
{
    db.m_lightTrans->setRotationY(val);
    db.m_lightEntity->addComponent(db.m_lightTrans);
    qDebug()<<"light rotate Y:"<<val;
}

void LoadObj::slotLightRotateZ(int val)
{
    db.m_lightTrans->setRotationZ(val);
    db.m_lightEntity->addComponent(db.m_lightTrans);
    qDebug()<<"light rotate Z:"<<val;
}

void LoadObj::slotPickerPressed(Qt3DRender::QPickEvent *pickEvent)
{
    //qDebug()<<"picker pressed";
}

void LoadObj::slotPickerMoved(Qt3DRender::QPickEvent *pickEvent)
{
    //qDebug()<<"picker moved";
}

void LoadObj::slotPickerReleased(Qt3DRender::QPickEvent *pickEvent)
{
    //qDebug()<<"picker release";
}

void LoadObj::slotPickerClicked(Qt3DRender::QPickEvent *pickEvent)
{
    //qDebug()<<"picker clicked";
    //这里显示的坐标值不是在窗口或者3D视图的位置值
    //qDebug()<<"local:"<<pickEvent->localIntersection().x()<<","<<pickEvent->localIntersection().y()<<","<<pickEvent->localIntersection().z();
    //qDebug()<<"world:"<<pickEvent->worldIntersection().x()<<","<<pickEvent->worldIntersection().y()<<","<<pickEvent->worldIntersection().z();
}

void LoadObj::slotPickerExited()
{
    //qDebug()<<"picker exited";
}

void LoadObj::mouseMoveEvent(QMouseEvent *event)
{
//    qDebug()<<"load obj widget mouse move";
//    event->ignore();
}

void LoadObj::mousePressEvent(QMouseEvent *event)
{
//    if(event->button() == Qt::LeftButton)
//    {
//        qDebug()<<event->globalPos();
//        qDebug()<<event->pos();
//    }
}

bool LoadObj::eventFilter(QObject *obj, QEvent *event)
{
//    if(obj == db.m_windowOn3D)
//    {
        //if(event->type() == QEvent::GraphicsSceneMouseMove)
        //if(event->type() == QEvent::MouseButtonPress)
//        if(event->type() == QEvent::MouseMove)
//            event->ignore();
//    }
    //return QWidget::eventFilter(obj,event);
}
